<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="generator" content="pandoc">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
  <title>硬件开发指南 – </title>
  <style type="text/css">code{white-space: pre;}</style>
  <style type="text/css">
div.sourceCode { overflow-x: auto; }
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
  margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; line-height: 100%; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
code > span.dt { color: #902000; } /* DataType */
code > span.dv { color: #40a070; } /* DecVal */
code > span.bn { color: #40a070; } /* BaseN */
code > span.fl { color: #40a070; } /* Float */
code > span.ch { color: #4070a0; } /* Char */
code > span.st { color: #4070a0; } /* String */
code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
code > span.ot { color: #007020; } /* Other */
code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
code > span.fu { color: #06287e; } /* Function */
code > span.er { color: #ff0000; font-weight: bold; } /* Error */
code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
code > span.cn { color: #880000; } /* Constant */
code > span.sc { color: #4070a0; } /* SpecialChar */
code > span.vs { color: #4070a0; } /* VerbatimString */
code > span.ss { color: #bb6688; } /* SpecialString */
code > span.im { } /* Import */
code > span.va { color: #19177c; } /* Variable */
code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code > span.op { color: #666666; } /* Operator */
code > span.bu { } /* BuiltIn */
code > span.ex { } /* Extension */
code > span.pp { color: #bc7a00; } /* Preprocessor */
code > span.at { color: #7d9029; } /* Attribute */
code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
  </style>
  <link rel="stylesheet" href="style.css">
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
  <meta name="viewport" content="width=device-width">
</head>
<body>
<h1>写给软件工程师看的硬件编程指南</h1>
<p>By <a href="https://www.phodal.com/">Phodal</a> (Follow Me: <a href="http://weibo.com/phodal">微博</a>、<a href="https://www.zhihu.com/people/phodal">知乎</a>、<a href="https://segmentfault.com/u/phodal">SegmentFault</a>)
</p>

<p>我的其他电子书：</p>
<ul>
<li>《<a href="https://github.com/phodal/ideabook">Phodal's Idea实战指南</a>》</li>
<li>《<a href="https://github.com/phodal/designiot">一步步搭建物联网系统</a>》</li>
<li>《<a href="https://github.com/phodal/github-roam">GitHub 漫游指南</a>》</li>
<li>《<a href="https://github.com/phodal/repractise">RePractise</a>》</li>
<li>《<a href="https://github.com/phodal/growth-ebook">Growth: 全栈增长工程师指南</a>》</li>
<li>《<a href="https://github.com/phodal/growth-in-action">Growth: 全栈增长工程师实战</a>》</li>
<li>《<a href="https://github.com/phodal/fe">我的职业是前端工程师</a>》</li>
</ul>

<p>微信公众号</p>
<p><img src="http://articles.phodal.com/qrcode.jpg" alt=""/></p>
<p>
当前为预览版，在使用的过程中遇到任何遇到请及时与我联系。阅读过程中问题，不烦在GitHub上提出来：
<a href="https://github.com/phodal/hardware-guide/issues">Issues</a>
</p>
<p>	
阅读过程中遇到语法错误、拼写错误、技术错误等等，不烦来个Pull Request，这样可以帮助到其他阅读这本电子书的童鞋。
</p>
<div style="width:800px">
<nav id="TOC">
<ul>
<li><a href="#前言">前言</a><ul>
<li><a href="#关于作者">关于作者</a></li>
</ul></li>
<li><a href="#基础篇">基础篇</a><ul>
<li><a href="#arduino-vs-esp8266-vs-raspberry-pi">Arduino vs ESP8266 vs Raspberry Pi</a><ul>
<li><a href="#arduino">Arduino</a></li>
</ul></li>
<li><a href="#概念">概念</a></li>
<li><a href="#pcb">PCB</a><ul>
<li><a href="#fritzing">Fritzing</a></li>
</ul></li>
<li><a href="#硬件">硬件</a></li>
<li><a href="#mcu-vs-cpu">MCU vs CPU</a></li>
<li><a href="#通讯">通讯</a></li>
</ul></li>
<li><a href="#第一部分-arduino-篇">第一部分 Arduino 篇</a></li>
<li><a href="#arduino-hello-world">Arduino Hello, World</a><ul>
<li><a href="#开发板选择">开发板选择</a></li>
<li><a href="#hello-world">hello, world</a><ul>
<li><a href="#setup">setup()</a></li>
<li><a href="#loop">loop()</a></li>
</ul></li>
<li><a href="#输入控制输出">输入控制输出</a><ul>
<li><a href="#电路图">电路图</a></li>
</ul></li>
</ul></li>
<li><a href="#arduino-传感器控制">Arduino 传感器控制</a><ul>
<li><a href="#传感器入门">传感器入门</a><ul>
<li><a href="#模拟元件与数字元件">模拟元件与数字元件</a></li>
</ul></li>
<li><a href="#超声波传感器">超声波传感器</a></li>
<li><a href="#控制继电器">控制继电器</a></li>
</ul></li>
<li><a href="#arduino-5110-显示">Arduino 5110 显示</a><ul>
<li><a href="#lcd">LCD</a></li>
<li><a href="#安装库">安装库</a></li>
<li><a href="#输出-hello-world">输出 hello, world</a></li>
</ul></li>
<li><a href="#arduino-processing">Arduino Processing</a><ul>
<li><a href="#串口输出">串口输出</a></li>
<li><a href="#复杂的例子mpu-6050">复杂的例子：MPU 6050</a></li>
</ul></li>
<li><a href="#arduino-ble-控制">Arduino BLE 控制</a><ul>
<li><a href="#蓝牙串口">蓝牙串口</a></li>
<li><a href="#与手机通讯">与手机通讯</a></li>
</ul></li>
<li><a href="#arduino-扩展板使用">Arduino 扩展板使用</a><ul>
<li><a href="#继电器">继电器</a></li>
<li><a href="#网络">网络</a></li>
</ul></li>
<li><a href="#arduino-esp8266-wifi">Arduino ESP8266 WiFi</a><ul>
<li><a href="#esp8266-设置">ESP8266 设置</a></li>
<li><a href="#arduino-wifi">Arduino WiFi</a></li>
</ul></li>
<li><a href="#第二部分-esp8266">第二部分 ESP8266</a></li>
<li><a href="#esp8266-基础">ESP8266 基础</a><ul>
<li><a href="#设置与-at-指令">设置与 AT 指令</a></li>
<li><a href="#nodemcu">NodeMCU</a></li>
</ul></li>
<li><a href="#esp8266-arduino-ide-展示">ESP8266 Arduino IDE 展示</a></li>
<li><a href="#esp8266-连接-arduino-uno">ESP8266 连接 Arduino UNO</a></li>
<li><a href="#esp8266-上传传感器数据">ESP8266 上传传感器数据</a><ul>
<li><a href="#adc-数据">ADC 数据</a></li>
<li><a href="#发送请求">发送请求</a></li>
<li><a href="#上传">上传</a></li>
</ul></li>
<li><a href="#esp8266-mqtt-控制">ESP8266 MQTT 控制</a><ul>
<li><a href="#mqtt">MQTT</a></li>
<li><a href="#moquitto">moquitto</a></li>
<li><a href="#section"></a></li>
</ul></li>
<li><a href="#esp8266-http-服务器">ESP8266 HTTP 服务器</a><ul>
<li><a href="#simple-http-server">Simple HTTP Server</a></li>
</ul></li>
<li><a href="#超越-esp8266">超越 ESP8266</a></li>
<li><a href="#第三部分-raspberry-pi">第三部分 Raspberry Pi</a></li>
<li><a href="#raspberry-pi-hello-world">Raspberry Pi Hello, world!</a><ul>
<li><a href="#镜像烧录">镜像烧录</a></li>
<li><a href="#ssh-连接">SSH 连接</a></li>
<li><a href="#python-控制-gpio">Python 控制 GPIO</a></li>
</ul></li>
<li><a href="#node.js-服务基础">Node.js 服务基础</a><ul>
<li><a href="#安装-node.js">安装 Node.js</a></li>
<li><a href="#express-hello-world">Express Hello, world</a></li>
<li><a href="#开机启动">开机启动</a></li>
</ul></li>
<li><a href="#摄像头-传感器-智能家居">摄像头 + 传感器 = 智能家居？</a><ul>
<li><a href="#红外传感器">红外传感器</a></li>
<li><a href="#视频流">视频流</a></li>
<li><a href="#拍照blabla">拍照，blabla</a></li>
</ul></li>
<li><a href="#与-esp8266-无线通讯">与 ESP8266 无线通讯</a><ul>
<li><a href="#建立服务">建立服务</a></li>
<li><a href="#广播">广播？</a></li>
</ul></li>
<li><a href="#arduino-ota-更新">Arduino OTA 更新</a><ul>
<li><a href="#服务端读取代码">服务端读取代码</a></li>
<li><a href="#arduino-cli-更新硬件">arduino-cli 更新硬件</a></li>
</ul></li>
<li><a href="#使用-mqtt-服务器">使用 MQTT 服务器</a><ul>
<li><a href="#mqtt-客户端">MQTT 客户端</a></li>
<li><a href="#使用-mosquittto">使用 mosquittto</a></li>
</ul></li>
<li><a href="#跟上潮流docker硬件微服务">跟上潮流：Docker、硬件微服务</a><ul>
<li><a href="#使用-docker">使用 Docker</a></li>
<li><a href="#硬件微服务">硬件微服务</a></li>
</ul></li>
<li><a href="#home-assistant-搭建">Home Assistant 搭建</a></li>
<li><a href="#home-assistant-整合">Home Assistant 整合</a></li>
<li><a href="#homekit-搭建">Homekit 搭建</a></li>
<li><a href="#homekit-整合">Homekit 整合</a></li>
<li><a href="#raspberry-pi-与智能音箱">Raspberry Pi 与智能音箱</a></li>
<li><a href="#raspberry-pi-自制智能音箱">Raspberry Pi 自制智能音箱</a></li>
<li><a href="#超越-raspberry-pi">超越 Raspberry Pi</a></li>
</ul>
</nav>
<h1 id="前言">前言</h1>
<p>最近这些日子里，当我和女朋友搬到了新的合租屋里，有了更大的空间——可以再次折腾硬件。便开始去玩一些硬件家居相关的内容，也顺便接上了 Amazon Echo、小米传感器、Broadlink、ESP8266 等等的硬件。</p>
<p>再加上正在编写的『玩点什么』网站，便也想整理一下硬件相关的资料。想着想着，便有了这一系列的电子书。</p>
<p>这是一本写给软件工程师看的硬件指南。</p>
<h2 id="关于作者">关于作者</h2>
<p>黄峰达（Phodal Huang）是一个创客、工程师、咨询师和作家。他毕业于西安文理学院电子信息工程专业，现作为一个咨询师就职于 ThoughtWorks 深圳。长期活跃于开源软件社区 GitHub，目前专注于物联网和前端领域。</p>
<p>作为一个开源软件作者，著有 Growth、Stepping、Lan、Echoesworks 等软件。其中开源学习应用 Growth，广受读者和用户好评，可在 APP Store 及各大 Android 应用商店下载。</p>
<p>作为一个技术作者，著有《自己动手设计物联网》（电子工业出版社）、《全栈应用开发：精益实践》（电子工业出版社，正在出版）。并在 GitHub 上开源有《Growth: 全栈增长工程师指南》、《GitHub 漫游指南》等七本电子书。</p>
<p>作为技术专家，他为英国 Packt 出版社审阅有物联网书籍《Learning IoT》、《Smart IoT》，前端书籍《Angular 2 Serices》、《Getting started with Angular》等技术书籍。</p>
<p>他热爱编程、写作、设计、旅行、hacking，你可以从他的个人网站：<a href="https://www.phodal.com/" class="uri">https://www.phodal.com/</a> 了解到更多的内容。</p>
<p>其它相关信息：</p>
<ul>
<li>微博：<a href="http://weibo.com/phodal" class="uri">http://weibo.com/phodal</a></li>
<li>GitHub： <a href="https://github.com/phodal" class="uri">https://github.com/phodal</a></li>
<li>知乎：<a href="https://www.zhihu.com/people/phodal" class="uri">https://www.zhihu.com/people/phodal</a></li>
<li>SegmentFault：<a href="https://segmentfault.com/u/phodal" class="uri">https://segmentfault.com/u/phodal</a></li>
</ul>
<p>当前为预览版，在使用的过程中遇到任何问题请及时与我联系。阅读过程中的问题，不妨在GitHub上提出来： <a href="https://github.com/phodal/fe/issues">Issues</a></p>
<p>阅读过程中遇到语法错误、拼写错误、技术错误等等，不妨来个Pull Request，这样可以帮助到其他阅读这本电子书的童鞋。</p>
<p>其他电子书：</p>
<ul>
<li>《<a href="https://github.com/phodal/ideabook">Phodal’s Idea实战指南</a>》</li>
<li>《<a href="https://github.com/phodal/designiot">一步步搭建物联网系统</a>》</li>
<li>《<a href="https://github.com/phodal/github-roam">GitHub 漫游指南</a>》</li>
<li>《<a href="https://github.com/phodal/repractise">RePractise</a>》</li>
<li>《<a href="https://github.com/phodal/growth-ebook">Growth: 全栈增长工程师指南</a>》</li>
<li>《<a href="https://github.com/phodal/growth-in-action">Growth: 全栈增长工程师实战</a>》</li>
<li>《<a href="http://github.com/phodal/fe">我的职业是前端工程师</a>》</li>
</ul>
<h1 id="基础篇">基础篇</h1>
<h2 id="arduino-vs-esp8266-vs-raspberry-pi">Arduino vs ESP8266 vs Raspberry Pi</h2>
<p>在这一系列的文章里，我们使用三个主要的开发板：</p>
<ul>
<li>Arduino。</li>
<li>ESP8266。</li>
<li>Raspberry Pi。</li>
</ul>
<p>这三个硬件分别代表着，三种不同类型的硬件爱好者的开发板。</p>
<h3 id="arduino">Arduino</h3>
<blockquote>
<p>Arduino，是一个开放源代码的单片机微控制器，它使用了Atmel AVR单片机，采用了开放源代码的软硬件平台，建构于简易输出/输入（simple I/O）接口板，并且具有使用类似Java、C语言的Processing/Wiring开发环境。<a href="#fn1" class="footnoteRef" id="fnref1"><sup>1</sup></a></p>
</blockquote>
<p>其包含了以下的特性<a href="#fn2" class="footnoteRef" id="fnref2"><sup>2</sup></a>:</p>
<ul>
<li>基于知识共享开放源代码的电路图设计。</li>
<li>免费下载，也可依需求自己修改，但需遵照姓名标示。您必须按照作者或授权人所指定的方式，表彰其姓名。</li>
<li>依相同方式分享，若您改变或转变著作，当散布该派生著作时，您需采用与本著作相同或类似的授权条款。</li>
<li>Arduino 可使用 ICSP 在线烧入器，将 Bootloader 烧入新的 IC 芯片。</li>
<li>可依据 Arduino 官方网站，获取硬件的设计档，加以调整电路板及组件，以匹配自己实际设计的需求</li>
<li>可简单地与感测器，各式各样的电子组件连接，如红外线、超音波、热敏电阻、光敏电阻、伺服马达…等。</li>
<li>支持多样的交互程序，如Adobe Flash, Max/MSP, VVVV, Pure Data, C, Processing…等。</li>
<li>使用低价格的微处理控制器（Atmel AVR）（ATMEGA 8,168,328等）。</li>
<li>USB接口，不需外接电源。另外有提供直流（DC）电源输入。</li>
</ul>
<p>当然，其最大的特色是，<strong>完善的社区及生态系统</strong>。几乎我们能想到的 Arduino 相关的创意，都可以在网上找到。如果没有的话，那么可能是你的创意不适合用于 Arduino。</p>
<p>Arduino 已然有一系列的相关硬件，就目前而言，最广泛的开发板，或者说是标准开发板是 Arduino UNO。</p>
<p>TODO: 相关 Arduino 硬件介绍</p>
<p>Arduino 最吸引人的是开创性的引入电子积木的概念，即开发板的扩展板可以直接叠加在开发板上使用，而无需额外的硬件。</p>
<p>TODO: 扩展板介绍。</p>
<p>Arduion IDE 基于 Processing 开发环境而开发的。</p>
<h2 id="概念">概念</h2>
<p>引脚</p>
<p>模电</p>
<p>数电</p>
<p>电流、电阻、电压</p>
<p>etc..</p>
<h2 id="pcb">PCB</h2>
<p>为了更好的向读者展示硬件连线，我们将使用 Fritzing 汇制硬件电路图。</p>
<h3 id="fritzing">Fritzing</h3>
<blockquote>
<p>Fritzing 是一个开源的硬件计划（initiative），它可以使电子元件变成任何人的创意素材。Fritzing 提供一个软件工具、一个社区网站，以及本着 Processing 和 Arduino 精神的服务，培养创造性的生态系统，允许用户记录他们的原型，与他人分享、用于课堂上的电子相关教学，以及布局和制造专业的pcb。</p>
</blockquote>
<p>Fritzing 的官网是：<a href="http://fritzing.org/" class="uri">http://fritzing.org/</a>。</p>
<p>因此，在开始之前我们需要在 Fritzing 的官网下载 Fritzing。当前它可以支持主流的操作系统：Windows、Linux、macOS，当然如果你想自己从源码编译一个 Fritzing，那也是可以的。除了中文和英语外，它还支持其它 17 种语言。</p>
<p>在其官网，除了能下载到该软件，还可以看到其它用户上传、汇制的 Fritzing 电路图等，它们可以免费下载，并引用到你的项目中。</p>
<p>LCEDA</p>
<h2 id="硬件">硬件</h2>
<p>Nokia 5110</p>
<p>温度、红外、距离、土壤</p>
<h2 id="mcu-vs-cpu">MCU vs CPU</h2>
<p>Input -&gt; MCU -&gt; Output</p>
<h2 id="通讯">通讯</h2>
<p>蓝牙、有线、</p>
<p>专用协议，blabla</p>
<h1 id="第一部分-arduino-篇">第一部分 Arduino 篇</h1>
<ul>
<li>Arduino + LED + 按钮控制</li>
<li>Arduino 读取传感器</li>
<li>Arduion + LCD 5100 显示传感器</li>
<li>Arduino 蓝牙通讯</li>
<li>Arduino Processing 可视化数据</li>
<li>Arduino 上传数据</li>
<li>Arduino 的可能性：+ Fritzing / Arduino + Johnny-Five</li>
</ul>
<h1 id="arduino-hello-world">Arduino Hello, World</h1>
<p>幸运的是，今天对硬件编程已经有了更多的方式，可以使用更高级的语言。除了在 Arduion 上使用 Processing 语言（可以视为 C）进行编程，还可以使用 JavaScript 等语言。我们会在后面的介绍：如何使用这些高级的语言来编程。</p>
<h2 id="开发板选择">开发板选择</h2>
<figure>
<img src="./images/arduino/arduinos.jpg" alt="Arduino 开发板示例" /><figcaption>Arduino 开发板示例</figcaption>
</figure>
<figure>
<img src="./images/arduino/shields.jpg" alt="扩展板" /><figcaption>扩展板</figcaption>
</figure>
<p>Arduino IDE 默认会安装相应环境的包，如果你的开发板不在这些环境里，如你使用的是 Arduino M0 开发板。那么，系统可能会检测出来，并自动为你安装相应的环境，如下图所示。</p>
<figure>
<img src="./images/arduino/arduino-install-package.png" alt="Arduino IDE 安装 Arduino M0 环境" /><figcaption>Arduino IDE 安装 Arduino M0 环境</figcaption>
</figure>
<p><code>注意</code>：安装过程中会下载一系列的工具，在这个过程里，可能会遇到一些“网络问题”。请尝试更换网络，或直到到“墙”的那外一边。</p>
<p>对于非官方的开发板来说，则需要开发者自己手动通过『开发板管理器』来安装，如 ESP8266 开发板。</p>
<h2 id="hello-world">hello, world</h2>
<p>与桌面端使用 print、puts、console.log 来输出 Hello, world 不同的是，点亮一个 LED 是 电子世界的 Hello, world。</p>
<p>在硬件世界里，没有 stdlib.h 这样的库，对于多数嵌入式系统来说，也没有屏幕。在这个时候，想要知道设备的状态，最简单的方式就是 LED。常见的，如路由器、电视等家电电器上的灯，都是嵌入式设备的状态。</p>
<p>官方的 Blink 示例如下：</p>
<div class="sourceCode"><pre class="sourceCode c"><code class="sourceCode c"><span class="dt">void</span> setup() {
  <span class="co">// initialize digital pin LED_BUILTIN as an output.</span>
  pinMode(LED_BUILTIN, OUTPUT);
}

<span class="co">// the loop function runs over and over again forever</span>
<span class="dt">void</span> loop() {
  digitalWrite(LED_BUILTIN, HIGH);   <span class="co">// turn the LED on (HIGH is the voltage level)</span>
  delay(<span class="dv">1000</span>);                       <span class="co">// wait for a second</span>
  digitalWrite(LED_BUILTIN, LOW);    <span class="co">// turn the LED off by making the voltage LOW</span>
  delay(<span class="dv">1000</span>);                       <span class="co">// wait for a second</span>
}</code></pre></div>
<p>接下来，要做的事情就比较简单了。从工具（ Tools ）中选择对应的开发板和端口，如下图所示：</p>
<figure>
<img src="./images/arduino/arduino-devices.png" alt="Arduino 选择设备" /><figcaption>Arduino 选择设备</figcaption>
</figure>
<p>我这里使用设置是 <code>Arduino M0 Pro</code>，对应的端口是：<code>/dev/tty.usbmodem1412</code>。</p>
<p>对于 Windows 用户来说，则是 COM 口——从设备管理器中找到对应的端口。</p>
<p>然后点击菜单中的 -&gt; 号，即上传（Upload，又可以称为烧录）。</p>
<figure>
<img src="./images/arduino/arduino-menu.png" alt="Arduino 菜单" /><figcaption>Arduino 菜单</figcaption>
</figure>
<p>再看看你的 Arduion，就发现上面的 LED 正在闪烁——一秒开一秒关。</p>
<h3 id="setup">setup()</h3>
<p>源码中的：</p>
<div class="sourceCode"><pre class="sourceCode c"><code class="sourceCode c"><span class="dt">int</span> main(<span class="dt">void</span>)
{
    init();
    setup();
    <span class="cf">for</span>(;;)
        loop();

    <span class="cf">return</span> <span class="dv">0</span>;
}</code></pre></div>
<h3 id="loop">loop()</h3>
<h2 id="输入控制输出">输入控制输出</h2>
<p>GOAL</p>
<p>SMART 原则</p>
<p>仍然采用的是官方的示例：</p>
<figure>
<img src="./images/arduino/fritzing-button.png" alt="Arduino 控制 LED 示例" /><figcaption>Arduino 控制 LED 示例</figcaption>
</figure>
<p>官方示例（<a href="https://www.arduino.cc/en/Tutorial/DigitalReadSerial">Digital Read Serial</a>）代码：</p>
<div class="sourceCode"><pre class="sourceCode c"><code class="sourceCode c"><span class="co">// digital pin 2 has a pushbutton attached to it. Give it a name:</span>
<span class="dt">int</span> pushButton = <span class="dv">2</span>;

<span class="co">// the setup routine runs once when you press reset:</span>
<span class="dt">void</span> setup() {
  <span class="co">// initialize serial communication at 9600 bits per second:</span>
  Serial.begin(<span class="dv">9600</span>);
  <span class="co">// make the pushbutton&#39;s pin an input:</span>
  pinMode(pushButton, INPUT);
}

<span class="co">// the loop routine runs over and over again forever:</span>
<span class="dt">void</span> loop() {
  <span class="co">// read the input pin:</span>
  <span class="dt">int</span> buttonState = digitalRead(pushButton);
  <span class="co">// print out the state of the button:</span>
  Serial.println(buttonState);
  delay(<span class="dv">1</span>);        <span class="co">// delay in between reads for stability</span>
}</code></pre></div>
<h3 id="电路图">电路图</h3>
<p>使用 Fritzing 画板时</p>
<figure>
<img src="./images/arduino/fritzing-example.jpg" />
</figure>
<p>我们所需要的连线图</p>
<figure>
<img src="./images/arduino/arduino-button.jpg" />
</figure>
<h1 id="arduino-传感器控制">Arduino 传感器控制</h1>
<h2 id="传感器入门">传感器入门</h2>
<blockquote>
<p>传感器是一种物理装置或生物器官，能够探测、感受外界的信号、物理条件（如光、热、湿度）或化学组成（如烟雾），并将探知的信息传递给其他装置或器官。“传感器”在新韦式大词典中定义为：“从一个系统接受功率，通常以另一种形式将功率送到第二个系统中的器件”。根据这个定义，传感器的作用是将一种能量转换成另一种能量形式，所以不少学者也用“换能器－Transducer”来称谓“传感器－Sensor”。[^wiki_sensor]</p>
</blockquote>
<p>[^wiki_sensor] : https://zh.wikipedia.org/wiki/%E4%BC%A0%E6%84%9F%E5%99%A8</p>
<h3 id="模拟元件与数字元件">模拟元件与数字元件</h3>
<h2 id="超声波传感器">超声波传感器</h2>
<figure>
<img src="./images/arduino/arduino-hs-sr04.png" alt="Arduion 超声波传感器连线图" /><figcaption>Arduion 超声波传感器连线图</figcaption>
</figure>
<p>使用到库：[NewPing]，GitHub 地址：<a href="https://github.com/PaulStoffregen/NewPing" class="uri">https://github.com/PaulStoffregen/NewPing</a></p>
<figure>
<img src="./images/arduino/download-zip.png" alt="下载 Zip 格式" /><figcaption>下载 Zip 格式</figcaption>
</figure>
<p>添加库</p>
<figure>
<img src="./images/arduinoadd-zip-library.png" alt="添加 NewPing 库" /><figcaption>添加 NewPing 库</figcaption>
</figure>
<div class="sourceCode"><pre class="sourceCode c"><code class="sourceCode c"><span class="pp">#include </span><span class="im">&lt;NewPing.h&gt;</span>

<span class="pp">#define TRIGGER_PIN  12  </span><span class="co">// Arduino pin tied to trigger pin on the ultrasonic sensor.</span>
<span class="pp">#define ECHO_PIN     11  </span><span class="co">// Arduino pin tied to echo pin on the ultrasonic sensor.</span>
<span class="pp">#define MAX_DISTANCE 200 </span><span class="co">// Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.</span>

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); <span class="co">// NewPing setup of pins and maximum distance.</span>

<span class="dt">void</span> setup() {
  Serial.begin(<span class="dv">115200</span>); <span class="co">// Open serial monitor at 115200 baud to see ping results.</span>
}

<span class="dt">void</span> loop() {
  delay(<span class="dv">50</span>);                     <span class="co">// Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.</span>
  Serial.print(<span class="st">&quot;Ping: &quot;</span>);
  Serial.print(sonar.ping_cm()); <span class="co">// Send ping, get distance in cm and print result (0 = outside set distance range)</span>
  Serial.println(<span class="st">&quot;cm&quot;</span>);
}</code></pre></div>
<figure>
<img src="serial-output-example.png" alt="输出示例" /><figcaption>输出示例</figcaption>
</figure>
<h2 id="控制继电器">控制继电器</h2>
<h1 id="arduino-5110-显示">Arduino 5110 显示</h1>
<h2 id="lcd">LCD</h2>
<h2 id="安装库">安装库</h2>
<p>项目地址：<a href="https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library">Adafruit PCD8544</a></p>
<figure>
<img src="./images/arduino/manage-library.png" alt="添加库" /><figcaption>添加库</figcaption>
</figure>
<figure>
<img src="./images/arduino/arduino-nokia-5110.png" alt="Arduino IDE 安装 5110" /><figcaption>Arduino IDE 安装 5110</figcaption>
</figure>
<p>一般来说，在安装完库后，都会有对应的示例。但是，这里的示例，稍微有一些复杂。</p>
<div class="sourceCode"><pre class="sourceCode c"><code class="sourceCode c"><span class="pp">#include </span><span class="im">&lt;Arduino.h&gt;</span>

<span class="pp">#include </span><span class="im">&lt;SPI.h&gt;</span>
<span class="pp">#include </span><span class="im">&lt;Adafruit_GFX.h&gt;</span>
<span class="pp">#include </span><span class="im">&lt;Adafruit_PCD8544.h&gt;</span>

<span class="co">// Pins</span>
<span class="dt">const</span> <span class="dt">int8_t</span> RST_PIN = D2;
<span class="dt">const</span> <span class="dt">int8_t</span> CE_PIN = D1;
<span class="dt">const</span> <span class="dt">int8_t</span> DC_PIN = D6;
<span class="co">//const int8_t DIN_PIN = D7;  // Uncomment for Software SPI</span>
<span class="co">//const int8_t CLK_PIN = D5;  // Uncomment for Software SPI</span>
<span class="dt">const</span> <span class="dt">int8_t</span> BL_PIN = D0;


<span class="co">// Software SPI with explicit CE pin.</span>
<span class="co">// Adafruit_PCD8544 display = Adafruit_PCD8544(CLK_PIN, DIN_PIN, DC_PIN, CE_PIN, RST_PIN);</span>

<span class="co">// Software SPI with CE tied to ground. Saves a pin but other pins can&#39;t be shared with other hardware.</span>
<span class="co">// Adafruit_PCD8544(int8_t CLK_PIN, int8_t DIN_PIN, int8_t DC_PIN, int8_t RST_PIN);</span>

<span class="co">// Hardware SPI based on hardware controlled SCK (SCLK) and MOSI (DIN) pins. CE is still controlled by any IO pin.</span>
<span class="co">// NOTE: MISO and SS will be set as an input and output respectively, so be careful sharing those pins!</span>
Adafruit_PCD8544 display = Adafruit_PCD8544(DC_PIN, CE_PIN, RST_PIN);

<span class="dt">void</span> setup() {
  Serial.begin(<span class="dv">9600</span>);
  Serial.println(<span class="st">&quot;</span><span class="sc">\n\n</span><span class="st">WeMos D1 Mini + Nokia 5110 PCD8544 84x48 Monochrome LCD</span><span class="sc">\n</span><span class="st">Using Adafruit_PCD8544 and Adafruit_GFX libraries</span><span class="sc">\n</span><span class="st">&quot;</span>);

  <span class="co">// Turn LCD backlight on</span>
  pinMode(BL_PIN, OUTPUT);
  digitalWrite(BL_PIN, HIGH);

  display.begin();
  display.setContrast(<span class="dv">60</span>);  <span class="co">// Adjust for your display</span>
  Serial.println(<span class="st">&quot;Show Adafruit logo bitmap&quot;</span>);

  <span class="co">// Show the Adafruit logo, which is preloaded into the buffer by their library</span>
  <span class="co">// display.clearDisplay();</span>
  delay(<span class="dv">2000</span>);

  display.clearDisplay();
  display.setTextSize(<span class="dv">1</span>);
  display.setTextColor(BLACK);
  display.setCursor(<span class="dv">0</span>,<span class="dv">0</span>);
  display.println(<span class="st">&quot;Hello, world!&quot;</span>);
  display.display();
}

<span class="dt">void</span> loop() {
}</code></pre></div>
<h2 id="输出-hello-world">输出 hello, world</h2>
<h1 id="arduino-processing">Arduino Processing</h1>
<h2 id="串口输出">串口输出</h2>
<h2 id="复杂的例子mpu-6050">复杂的例子：MPU 6050</h2>
<h1 id="arduino-ble-控制">Arduino BLE 控制</h1>
<h2 id="蓝牙串口">蓝牙串口</h2>
<p>Bluno 等自带蓝牙的开发板</p>
<h2 id="与手机通讯">与手机通讯</h2>
<p>React Native / Cordova ???</p>
<h1 id="arduino-扩展板使用">Arduino 扩展板使用</h1>
<p>I don’t know</p>
<h2 id="继电器">继电器</h2>
<h2 id="网络">网络</h2>
<figure>
<img src="./images/arduino/arduino-ethernet.png" alt="Arduion 以太网扩展板" /><figcaption>Arduion 以太网扩展板</figcaption>
</figure>
<h1 id="arduino-esp8266-wifi">Arduino ESP8266 WiFi</h1>
<h2 id="esp8266-设置">ESP8266 设置</h2>
<h2 id="arduino-wifi">Arduino WiFi</h2>
<h1 id="第二部分-esp8266">第二部分 ESP8266</h1>
<ul>
<li>ESP8266 基础 + 连接 WiFi / NodeMCU</li>
<li>ESP8266 Arduino IDE ??</li>
<li>ESP8266 上传 Arduino 数据</li>
<li>？ ESP8266 读取传感器（ADC？）），并上传数据</li>
<li>ESP8266 MQTT 示例</li>
<li>ESP8266 作为 HTTP 服务器示例</li>
<li>更多的可能性探索：Mongoose OS、Johnny-Five、智能家居</li>
</ul>
<h1 id="esp8266-基础">ESP8266 基础</h1>
<h2 id="设置与-at-指令">设置与 AT 指令</h2>
<h2 id="nodemcu">NodeMCU</h2>
<h1 id="esp8266-arduino-ide-展示">ESP8266 Arduino IDE 展示</h1>
<h1 id="esp8266-连接-arduino-uno">ESP8266 连接 Arduino UNO</h1>
<h1 id="esp8266-上传传感器数据">ESP8266 上传传感器数据</h1>
<h3 id="adc-数据">ADC 数据</h3>
<h3 id="发送请求">发送请求</h3>
<div class="sourceCode"><pre class="sourceCode c"><code class="sourceCode c"><span class="co">/**</span>
<span class="co"> * BasicHTTPClient.ino</span>
<span class="co"> *</span>
<span class="co"> *  Created on: 24.05.2015</span>
<span class="co"> *</span>
<span class="co"> */</span>

<span class="pp">#include </span><span class="im">&lt;Arduino.h&gt;</span>

<span class="pp">#include </span><span class="im">&lt;ESP8266WiFi.h&gt;</span>
<span class="pp">#include </span><span class="im">&lt;ESP8266WiFiMulti.h&gt;</span>

<span class="pp">#include </span><span class="im">&lt;ESP8266HTTPClient.h&gt;</span>

<span class="pp">#define USE_SERIAL Serial</span>

ESP8266WiFiMulti WiFiMulti;

<span class="dt">void</span> setup() {

    USE_SERIAL.begin(<span class="dv">115200</span>);
   <span class="co">// USE_SERIAL.setDebugOutput(true);</span>

    USE_SERIAL.println();
    USE_SERIAL.println();
    USE_SERIAL.println();

    <span class="cf">for</span>(<span class="dt">uint8_t</span> t = <span class="dv">4</span>; t &gt; <span class="dv">0</span>; t--) {
        USE_SERIAL.printf(<span class="st">&quot;[SETUP] WAIT %d...</span><span class="sc">\n</span><span class="st">&quot;</span>, t);
        USE_SERIAL.flush();
        delay(<span class="dv">1000</span>);
    }

    WiFiMulti.addAP(<span class="st">&quot;SSID&quot;</span>, <span class="st">&quot;PASSWORD&quot;</span>);

}

<span class="dt">void</span> loop() {
    <span class="co">// wait for WiFi connection</span>
    <span class="cf">if</span>((WiFiMulti.run() == WL_CONNECTED)) {

        HTTPClient http;

        USE_SERIAL.print(<span class="st">&quot;[HTTP] begin...</span><span class="sc">\n</span><span class="st">&quot;</span>);
        <span class="co">// configure traged server and url</span>
        <span class="co">//http.begin(&quot;https://192.168.1.12/test.html&quot;, &quot;7a 9c f4 db 40 d3 62 5a 6e 21 bc 5c cc 66 c8 3e a1 45 59 38&quot;); //HTTPS</span>
        http.begin(<span class="st">&quot;http://192.168.1.12/test.html&quot;</span>); <span class="co">//HTTP</span>

        USE_SERIAL.print(<span class="st">&quot;[HTTP] GET...</span><span class="sc">\n</span><span class="st">&quot;</span>);
        <span class="co">// start connection and send HTTP header</span>
        <span class="dt">int</span> httpCode = http.GET();

        <span class="co">// httpCode will be negative on error</span>
        <span class="cf">if</span>(httpCode &gt; <span class="dv">0</span>) {
            <span class="co">// HTTP header has been send and Server response header has been handled</span>
            USE_SERIAL.printf(<span class="st">&quot;[HTTP] GET... code: %d</span><span class="sc">\n</span><span class="st">&quot;</span>, httpCode);

            <span class="co">// file found at server</span>
            <span class="cf">if</span>(httpCode == HTTP_CODE_OK) {
                String payload = http.getString();
                USE_SERIAL.println(payload);
            }
        } <span class="cf">else</span> {
            USE_SERIAL.printf(<span class="st">&quot;[HTTP] GET... failed, error: %s</span><span class="sc">\n</span><span class="st">&quot;</span>, http.errorToString(httpCode).c_str());
        }

        http.end();
    }

    delay(<span class="dv">10000</span>);
}</code></pre></div>
<h3 id="上传">上传</h3>
<h1 id="esp8266-mqtt-控制">ESP8266 MQTT 控制</h1>
<h3 id="mqtt">MQTT</h3>
<h3 id="moquitto">moquitto</h3>
<h3 id="section"></h3>
<p><a href="https://github.com/tuanpmt/esp_mqtt" class="uri">https://github.com/tuanpmt/esp_mqtt</a></p>
<h1 id="esp8266-http-服务器">ESP8266 HTTP 服务器</h1>
<h3 id="simple-http-server">Simple HTTP Server</h3>
<div class="sourceCode"><pre class="sourceCode c"><code class="sourceCode c"><span class="pp">#include </span><span class="im">&lt;ESP8266WiFi.h&gt;</span>
<span class="pp">#include </span><span class="im">&lt;ESP8266WebServer.h&gt;</span>
 
ESP8266WebServer server(<span class="dv">80</span>);
 
<span class="dt">void</span> setup() {
 
  Serial.begin(<span class="dv">115200</span>);
  WiFi.begin(<span class="st">&quot;Network name&quot;</span>, <span class="st">&quot;Password&quot;</span>);  <span class="co">//Connect to the WiFi network</span>
 
  <span class="cf">while</span> (WiFi.status() != WL_CONNECTED) {  <span class="co">//Wait for connection</span>
    delay(<span class="dv">500</span>);
    Serial.println(<span class="st">&quot;Waiting to connect…&quot;</span>);
  }
 
  Serial.print(<span class="st">&quot;IP address: &quot;</span>);
  Serial.println(WiFi.localIP());  <span class="co">//Print the local IP</span>
 
  server.on(<span class="st">&quot; / other&quot;</span>, []() {   <span class="co">//Define the handling function for the path</span>
 
    server.send(<span class="dv">200</span>, <span class="st">&quot;text / plain&quot;</span>, <span class="st">&quot;Other URL&quot;</span>);
 
  });
 
  server.on(<span class="st">&quot; / &quot;</span>, handleRootPath);    <span class="co">//Associate the handler function to the path</span>
  server.begin();                                       <span class="co">//Start the server</span>
  Serial.println(<span class="st">&quot;Server listening&quot;</span>);
}
 
<span class="dt">void</span> loop() {
  server.handleClient();
}
 
<span class="dt">void</span> handleRootPath() {
  server.send(<span class="dv">200</span>, <span class="st">&quot;text/plain&quot;</span>, <span class="st">&quot;Hello world&quot;</span>); 
}</code></pre></div>
<h1 id="超越-esp8266">超越 ESP8266</h1>
<h1 id="第三部分-raspberry-pi">第三部分 Raspberry Pi</h1>
<ul>
<li>Hello, world!</li>
<li>Node.js 服务 - 开机启动，blabla</li>
<li>连接 Arduino、自动编程？ OTA ？</li>
<li>Raspberry Pi as PC Camera + Sensors ???</li>
<li>Raspberry Pi &lt;-&gt; ESP8266 / Node.js Example</li>
<li>MQTT Server</li>
<li>IoT Server + Database?</li>
</ul>
<h1 id="raspberry-pi-hello-world">Raspberry Pi Hello, world!</h1>
<h3 id="镜像烧录">镜像烧录</h3>
<h3 id="ssh-连接">SSH 连接</h3>
<h3 id="python-控制-gpio">Python 控制 GPIO</h3>
<h1 id="node.js-服务基础">Node.js 服务基础</h1>
<h3 id="安装-node.js">安装 Node.js</h3>
<h3 id="express-hello-world">Express Hello, world</h3>
<h3 id="开机启动">开机启动</h3>
<h1 id="摄像头-传感器-智能家居">摄像头 + 传感器 = 智能家居？</h1>
<h3 id="红外传感器">红外传感器</h3>
<h3 id="视频流">视频流</h3>
<h3 id="拍照blabla">拍照，blabla</h3>
<h1 id="与-esp8266-无线通讯">与 ESP8266 无线通讯</h1>
<h3 id="建立服务">建立服务</h3>
<h3 id="广播">广播？</h3>
<h1 id="arduino-ota-更新">Arduino OTA 更新</h1>
<h3 id="服务端读取代码">服务端读取代码</h3>
<h3 id="arduino-cli-更新硬件">arduino-cli 更新硬件</h3>
<h1 id="使用-mqtt-服务器">使用 MQTT 服务器</h1>
<h3 id="mqtt-客户端">MQTT 客户端</h3>
<h3 id="使用-mosquittto">使用 mosquittto</h3>
<h1 id="跟上潮流docker硬件微服务">跟上潮流：Docker、硬件微服务</h1>
<h3 id="使用-docker">使用 Docker</h3>
<h3 id="硬件微服务">硬件微服务</h3>
<h1 id="home-assistant-搭建">Home Assistant 搭建</h1>
<h1 id="home-assistant-整合">Home Assistant 整合</h1>
<h1 id="homekit-搭建">Homekit 搭建</h1>
<h1 id="homekit-整合">Homekit 整合</h1>
<h1 id="raspberry-pi-与智能音箱">Raspberry Pi 与智能音箱</h1>
<h1 id="raspberry-pi-自制智能音箱">Raspberry Pi 自制智能音箱</h1>
<h1 id="超越-raspberry-pi">超越 Raspberry Pi</h1>
<section class="footnotes">
<hr />
<ol>
<li id="fn1"><p>源自维基百科，https://zh.wikipedia.org/wiki/Arduino<a href="#fnref1">↩</a></p></li>
<li id="fn2"><p>源自维基百科，https://zh.wikipedia.org/wiki/Arduino<a href="#fnref2">↩</a></p></li>
</ol>
</section>
</body>
</html>
